#ifndef _NET_TDSOCKET_H_
#define _NET_TDSOCKET_H_

#include <limits.h>

#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

#ifdef WIN32
#include <io.h>
#include <winsock2.h>
#include <Ws2tcpip.h>

#define IPTOS_LOWDELAY  0x10  /// 
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <errno.h>
#endif

#ifdef _LINUX
#include <linux/if_packet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <sys/sendfile.h>
#endif

#ifndef WIN32
#include <sys/time.h>
#include <sys/uio.h>
#include <unistd.h>	
#include <fcntl.h>
#endif


#ifdef __cplusplus
extern "C"
{
#endif

	/*---------------------------------------------------------------------------*/
	/*                                                                           */
	/* Type Definition Macros                                                    */
	/*                                                                           */
	/*---------------------------------------------------------------------------*/
#ifndef __WORDSIZE
	/* Assume 32 */
#define __WORDSIZE 32
#endif

#ifndef WIN32
	typedef int            SOCKET;
#endif

#ifdef WIN32
	struct iovec {
		void  *iov_base;
		size_t iov_len;
	};
#endif

#ifdef WIN32
	typedef int socklen_t;
#endif

#if defined(WIN32)
#elif (__WORDSIZE == 32)
	__extension__
		typedef long long int          hint64;
	__extension__
		typedef unsigned long long int huint64;
#elif (__WORDSIZE == 64)
	typedef unsigned long int huint64;
	typedef long int          hint64;
#endif

#ifdef WIN32
#ifndef UINT8_MAX
#define UINT8_MAX  (UCHAR_MAX)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (USHRT_MAX)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (ULONG_MAX)
#endif

#if __WORDSIZE == 64
#define SIZE_MAX (18446744073709551615UL)
#else
#ifndef SIZE_MAX
#define SIZE_MAX (4294967295U)
#endif
#endif
#endif

#if defined(WIN32)
#define ssize_t size_t
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef htonll
#ifdef _BIG_ENDIAN
#define htonll(x)   (x)
#define ntohll(x)   (x)
#else
#define htonll(x)   ((((huint64)htonl(x)) << 32) + htonl(x >> 32))
#define ntohll(x)   ((((huint64)ntohl(x)) << 32) + ntohl(x >> 32))
#endif
#endif

	/*---------------------------------------------------------------------------*/
	/*                                                                           */
	/* Socket Macros                                                             */
	/*                                                                           */
	/*---------------------------------------------------------------------------*/
#ifndef SHUT_RD
#define SHUT_RD                0
#endif
#ifndef SHUT_WR
#define SHUT_WR                1
#endif
#ifndef SHUT_RDWR
#define SHUT_RDWR              2
#endif

#ifdef WIN32
#pragma comment(lib,"ws2_32.lib")
#define ACCEPT(a,b,c)          accept(a,b,c)
#define CONNECT(a,b,c)         connect(a,b,c)
#define CLOSE(a)               closesocket(a)
#define READ(a,b,c)            _read(a,b,c)
#define RECV(a,b,c,d)          recv(a, (char *)b, c, d)
#define RECVFROM(a,b,c,d,e,f)  recvfrom(a, (char *)b, c, d, (sockaddr *)e, (int *)f)
#define RECV_FLAGS             MSG_WAITALL
#define SELECT(a,b,c,d,e)      select((i32)a,b,c,d,e)
#define SEND(a,b,c,d)          send(a, (const char *)b, (int)c, d)
#define SENDTO(a,b,c,d,e,f)    sendto(a, (const char *)b, (int)c, d, e, f)
#define SEND_FLAGS             0
#define SENDFILE(a,b,c,d)      sendfile(a, b, c, d)
#define SET_SOCKET_ERROR(x,y)  errno=y
#define SOCKET_ERROR_INTERUPT  EINTR
#define SOCKET_ERROR_TIMEDOUT  EAGAIN
#define WRITE(a,b,c)           write(a,b,c)
#define WRITEV(a,b,c)          Writev(b, c)
#define GETSOCKOPT(a,b,c,d,e)  getsockopt(a,b,c,(char *)d, (int *)e)
#define SETSOCKOPT(a,b,c,d,e)  setsockopt(a,b,c,(char *)d, (int)e)
#define GETHOSTBYNAME(a)       gethostbyname((const char *)a)
#define LSEEK(a,b,c)           _lseek(a,b,c)
#else
#define ACCEPT(a,b,c)          accept(a,b,c)
#define CONNECT(a,b,c)         connect(a,b,c)
#define CLOSE(a)               close(a)
#define READ(a,b,c)            read(a,b,c)
#define RECV(a,b,c,d)          recv(a, (void *)b, c, d)
#define RECVFROM(a,b,c,d,e,f)  recvfrom(a, (char *)b, c, d, (sockaddr *)e, f)
#define RECV_FLAGS             MSG_WAITALL
#define SELECT(a,b,c,d,e)      select(a,b,c,d,e)
#define SEND(a,b,c,d)          send(a, (const i8 *)b, c, d)
#define SENDTO(a,b,c,d,e,f)    sendto(a, (const i8 *)b, c, d, e, f)
#define SEND_FLAGS             0
#define SENDFILE(a,b,c,d)      sendfile(a, b, c, d)
#define SET_SOCKET_ERROR(x,y)  errno=y
#define SOCKET_ERROR_INTERUPT  EINTR
#define SOCKET_ERROR_TIMEDOUT  EAGAIN
#define WRITE(a,b,c)           write(a,b,c)
#define WRITEV(a,b,c)          writev(a, b, c)
#define GETSOCKOPT(a,b,c,d,e)  getsockopt((int)a,(int)b,(int)c,(void *)d,(socklen_t *)e)
#define SETSOCKOPT(a,b,c,d,e)  setsockopt((int)a,(int)b,(int)c,(const void *)d,(int)e)
#define GETHOSTBYNAME(a)       gethostbyname((const char *)a)
#define LSEEK(a,b,c)           lseek(a,b,c)
#endif


	/*---------------------------------------------------------------------------*/
	/*                                                                           */
	/* File Macros                                                               */
	/*                                                                           */
	/*---------------------------------------------------------------------------*/
#define STRUCT_STAT         struct stat
#define LSTAT(x,y)          lstat(x,y)
#define FILE_HANDLE         FILE *
#define CLEARERR(x)         clearerr(x)
#define FCLOSE(x)           fclose(x)
#define FEOF(x)             feof(x)
#define FERROR(x)           ferror(x)
#define FFLUSH(x)           fflush(x)
#define FILENO(s)           fileno(s)
#define FOPEN(x,y)          fopen(x, y)
	//#define FREAD(a,b,c,d)      fread(a, b, c, d)
#define FSTAT(s, st)        fstat(FILENO(s), st)
	//#define FWRITE(a,b,c,d)     fwrite(a, b, c, d)
#define STAT_BLK_SIZE(x)    ((x).st_blksize)


	/*---------------------------------------------------------------------------*/
	/*                                                                           */
	/* Misc Macros                                                               */
	/*                                                                           */
	/*---------------------------------------------------------------------------*/
#if defined(WIN32)
#define GET_CLOCK_COUNT(x) QueryPerformanceCounter((LARGE_INTEGER *)x)
#else
#define GET_CLOCK_COUNT(x) gettimeofday(x, NULL)
#endif

#if defined(WIN32)
#define STRTOULL(x) _atoi64(x)
#else
#define STRTOULL(x) strtoull(x, NULL, 10)
#endif

#if defined(WIN32)
#define SNPRINTF _snprintf
#define PRINTF   printf
#define VPRINTF  vprintf
#define FPRINTF  fprintf
#else 
#define SNPRINTF snprintf
#define PRINTF   printf
#define VPRINTF  vprintf
#define FPRINTF  fprintf
#endif

#ifdef __cplusplus
}
#endif


#include "utils/TDMacro.h"
#include <vector>

//-----------------------------------------------------------------------------
// General class macro definitions and typedefs
//-----------------------------------------------------------------------------
#ifndef INVALID_SOCKET
#define INVALID_SOCKET    ~(0)
#endif

#define SOCKET_SENDFILE_BLOCKSIZE 8192

/// Provides a platform independent class to for socket development.
/// This class is designed to abstract socket communication development in a 
/// platform independent manner. 
/// - Socket types
///  -# CActiveSocket Class
///  -# CPassiveSocket Class
class TDSocket {
public:
	/// Defines the three possible states for shuting down a socket.
	typedef enum
	{
		Receives = SHUT_RD, ///< Shutdown passive socket.
		Sends = SHUT_WR,    ///< Shutdown active socket.
		Both = SHUT_RDWR    ///< Shutdown both active and passive sockets.
	} CShutdownMode;

	/// Defines the socket types defined by CSimpleSocket class.
	typedef enum
	{
		SocketTypeInvalid,   ///< Invalid socket type.
		SocketTypeTcp,       ///< Defines socket as TCP socket.
		SocketTypeUdp,       ///< Defines socket as UDP socket.
		SocketTypeTcp6,      ///< Defines socket as IPv6 TCP socket.
		SocketTypeUdp6,      ///< Defines socket as IPv6 UDP socket.
		SocketTypeRaw        ///< Provides raw network protocol access.
	} CSocketType;

	/// Defines all error codes handled by the CSimpleSocket class.
	typedef enum
	{
		SocketError = -1,          ///< Generic socket error translates to error below.
		SocketSuccess = 0,         ///< No socket error.
		SocketInvalidSocket,       ///< Invalid socket handle.
		SocketInvalidAddress,      ///< Invalid destination address specified.
		SocketInvalidPort,         ///< Invalid destination port specified.
		SocketConnectionRefused,   ///< No server is listening at remote address.
		SocketTimedout,            ///< Timed out while attempting operation.
		SocketEwouldblock,         ///< Operation would block if socket were blocking.
		SocketNotconnected,        ///< Currently not connected.
		SocketEinprogress,         ///< Socket is non-blocking and the connection cannot be completed immediately
		SocketInterrupted,         ///< Call was interrupted by a signal that was caught before a valid connection arrived.
		SocketConnectionAborted,   ///< The connection has been aborted.
		SocketProtocolError,       ///< Invalid protocol for operation.
		SocketFirewallError,       ///< Firewall rules forbid connection.
		SocketInvalidSocketBuffer, ///< The receive buffer point outside the process's address space.
		SocketConnectionReset,     ///< Connection was forcibly closed by the remote host.
		SocketAddressInUse,        ///< Address already in use.
		SocketInvalidPointer,      ///< Pointer type supplied as argument is invalid.
		SocketEunknown             ///< Unknown error please report to mark@carrierlabs.com
	} CSocketError;

public:
	TDSocket(SOCKET socket = INVALID_SOCKET, CSocketType nType = SocketTypeTcp);
	TDSocket(TDSocket &socket);

	virtual ~TDSocket()
	{
		m_pBuffer.clear();
		//Close();
	};

	/// Initialize instance of CSocket.  This method MUST be called before an
	/// object can be used. Errors : CSocket::SocketProtocolError, 
	/// CSocket::SocketInvalidSocket,
	/// @return true if properly initialized.
	virtual bool Initialize(void);

	/// Close socket
	/// @return true if successfully closed otherwise returns false.
	virtual bool Close(void);

	/// Shutdown shut down socket send and receive operations
	///	CShutdownMode::Receives - Disables further receive operations.
	///	CShutdownMode::Sends    - Disables further send operations.
	///	CShutdownBoth::         - Disables further send and receive operations.
	/// @param nShutdown specifies the type of shutdown. 
	/// @return true if successfully shutdown otherwise returns false.
	virtual bool Shutdown(CShutdownMode nShutdown);

	/// Examine the socket descriptor sets currently owned by the instance of
	/// the socket class (the readfds, writefds, and errorfds parameters) to 
	/// see whether some of their descriptors are ready for reading, are ready 
	/// for writing, or have an exceptional condition pending, respectively.
	/// Block until an event happens on the specified file descriptors.
	/// @return true if socket has data ready, or false if not ready or timed out.
	virtual bool Select(void) { return Select(0, 0); };

	/// Examine the socket descriptor sets currently owned by the instance of
	/// the socket class (the readfds, writefds, and errorfds parameters) to 
	/// see whether some of their descriptors are ready for reading, are ready 
	/// for writing, or have an exceptional condition pending, respectively.
	/// @param nTimeoutSec timeout in seconds for select.
	/// @param nTimeoutUSec timeout in micro seconds for select.
	/// @return true if socket has data ready, or false if not ready or timed out.
	virtual bool Select(i32 nTimeoutSec, i32 nTimeoutUSec);

	/// Does the current instance of the socket object contain a valid socket
	/// descriptor.
	///  @return true if the socket object contains a valid socket descriptor.
	virtual bool IsSocketValid(void) { return (m_socket != SocketError && m_socket != INVALID_SOCKET); };

	/// Provides a standard error code for cross platform development by
	/// mapping the operating system error to an error defined by the CSocket
	/// class.
	void TranslateSocketError(void);

	/// Attempts to receive a block of data on an established connection.	
	/// @param nMaxBytes maximum number of bytes to receive.
	/// @return number of bytes actually received.
	/// @return of zero means the connection has been shutdown on the other side.
	/// @return of -1 means that an error has occurred.
	virtual i32 Receive(i32 nMaxBytes = 1);

	/// Attempts to send a block of data on an established connection.
	/// @param pBuf block of data to be sent.
	/// @param bytesToSend size of data block to be sent.
	/// @return number of bytes actually sent.
	/// @return of zero means the connection has been shutdown on the other side.
	/// @return of -1 means that an error has occurred.
	virtual i32 Send(const char *pBuf, size_t bytesToSend);

	/// Attempts to send at most nNumItem blocks described by sendVector 
	/// to the socket descriptor associated with the socket object.
	/// @param sendVector pointer to an array of iovec structures
	/// @param nNumItems number of items in the vector to process
	/// <br>\b NOTE: Buffers are processed in the order specified.
	/// @return number of bytes actually sent, return of zero means the
	/// connection has been shutdown on the other side, and a return of -1
	/// means that an error has occurred.
	virtual i32 Send(const struct iovec *sendVector, i32 nNumItems);

	/// Copies data between one file descriptor and another.  
	/// On some systems this copying is done within the kernel, and thus is 
	/// more efficient than the combination of CSimpleSocket::Send and 
	/// CSimpleSocket::Receive, which would require transferring data to and 
	/// from user space.  
	/// <br>\b Note: This is available on all implementations, but the kernel 
	/// implementation is only available on Unix type systems.
	/// @param nOutFd descriptor opened for writing.
	/// @param nInFd descriptor opened for reading.
	/// @param pOffset from which to start reading data from input file.
	/// @param nCount number of bytes to copy between file descriptors.
	/// @return number of bytes written to the out socket descriptor.
	virtual i32 SendFile(i32 nOutFd, i32 nInFd, off_t *pOffset, i32 nCount);

	/// Returns blocking/non-blocking state of socket.
	/// @return true if the socket is non-blocking, else return false.
	bool IsNonblocking(void) { return (m_bIsBlocking == false); };

	bool IsConnect() { return IsSocketValid() && m_bIsConnect; }

	/// Set the socket to blocking.
	/// @return true if successful set to blocking, else return false;
	bool SetBlocking(void);

	/// Set the socket as non-blocking.
	/// @return true if successful set to non-blocking, else return false;
	bool SetNonblocking(void);

	/// Get a pointer to internal receive buffer.  The user MUST not free this
	/// pointer when finished.  This memory is managed internally by the CSocket 
	/// class.
	/// @return pointer to data if valid, else returns NULL.
	u8 *GetData(void)  { return &m_pBuffer[0]; };

	/// Returns the number of bytes received on the last call to 
	/// CSocket::Receive().
	/// @return number of bytes received.
	i32 GetBytesReceived(void) { return m_nBytesReceived; };

	/// Returns the number of bytes sent on the last call to 
	/// CSocket::Send().
	/// @return number of bytes sent.
	i32 GetBytesSent(void) { return m_nBytesSent; };

	/// Controls the actions taken when CSimpleSocket::Close is executed on a 
	/// socket object that has unsent data.  The default value for this option 
	/// is \b off.
	/// - Following are the three possible scenarios.
	///  -# \b bEnable is false, CSimpleSocket::Close returns immediately, but 
	///  any unset data is transmitted (after CSimpleSocket::Close returns)
	///  -# \b bEnable is true and \b nTime is zero, CSimpleSocket::Close return 
	/// immediately and any unsent data is discarded.
	///  -# \b bEnable is true and \b nTime is nonzero, CSimpleSocket::Close does
	///  not return until all unsent data is transmitted (or the connection is 
	///  Closed by the remote system).
	/// <br><p>
	/// @param bEnable true to enable option false to disable option.
	/// @param nTime time in seconds to linger.
	/// @return true if option successfully set
	bool SetOptionLinger(bool bEnable, u16 nTime);

	/// Tells the kernel that even if this port is busy (in the TIME_WAIT state),
	/// go ahead and reuse it anyway.  If it is busy, but with another state, 
	/// you will still get an address already in use error.
	/// @return true if option successfully set
	bool SetOptionReuseAddr();

	/// Gets the timeout value that specifies the maximum number of seconds a
	/// call to CSimpleSocket::Open waits until it completes. 
	/// @return the length of time in seconds
	i32 GetConnectTimeoutSec(void) { return  m_stConnectTimeout.tv_sec; };

	/// Gets the timeout value that specifies the maximum number of microseconds
	/// a call to CSimpleSocket::Open waits until it completes. 
	/// @return the length of time in microseconds
	i32 GetConnectTimeoutUSec(void) { return  m_stConnectTimeout.tv_usec; };

	/// Sets the timeout value that specifies the maximum amount of time a call 
	/// to CSimpleSocket::Receive waits until it completes. Use the method
	/// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
	/// If a call to CSimpleSocket::Receive has blocked for the specified length of
	/// time without receiving additional data, it returns with a partial count 
	/// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 
	/// were received. 
	/// @param nConnectTimeoutSec of timeout in seconds.
	/// @param nConnectTimeoutUsec of timeout in microseconds.
	/// @return true if socket connection timeout was successfully set.
	void SetConnectTimeout(i32 nConnectTimeoutSec, i32 nConnectTimeoutUsec = 0)
	{
		m_stConnectTimeout.tv_sec = nConnectTimeoutSec;
		m_stConnectTimeout.tv_usec = nConnectTimeoutUsec;
	};

	/// Gets the timeout value that specifies the maximum number of seconds a
	/// a call to CSimpleSocket::Receive waits until it completes. 
	/// @return the length of time in seconds
	i32 GetReceiveTimeoutSec(void) { return  m_stRecvTimeout.tv_sec; };

	/// Gets the timeout value that specifies the maximum number of microseconds
	/// a call to CSimpleSocket::Receive waits until it completes. 
	/// @return the length of time in microseconds
	i32 GetReceiveTimeoutUSec(void) { return  m_stRecvTimeout.tv_usec; };

	/// Sets the timeout value that specifies the maximum amount of time a call 
	/// to CSimpleSocket::Receive waits until it completes. Use the method
	/// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
	/// If a call to CSimpleSocket::Receive has blocked for the specified length of
	/// time without receiving additional data, it returns with a partial count 
	/// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 
	/// were received. 
	///  @param nRecvTimeoutSec of timeout in seconds.
	///  @param nRecvTimeoutUsec of timeout in microseconds.
	///  @return true if socket timeout was successfully set.
	bool SetReceiveTimeout(i32 nRecvTimeoutSec, i32 nRecvTimeoutUsec = 0);

	/// Enable/disable multicast for a socket.  This options is only valid for
	/// socket descriptors of type CSimpleSocket::SocketTypeUdp.
	/// @return true if multicast was enabled or false if socket type is not
	/// CSimpleSocket::SocketTypeUdp and the error will be set to 
	/// CSimpleSocket::SocketProtocolError 
	bool SetMulticast(bool bEnable, u8 multicastTTL = 1);

	/// Return true if socket is multicast or false is socket is unicast
	/// @return true if multicast is enabled
	bool GetMulticast() { return m_bIsMulticast; };

	/// Bind socket to a specific interface when using multicast.
	/// @return true if successfully bound to interface
	bool BindInterface(u8 *pInterface);

	/// Gets the timeout value that specifies the maximum number of seconds a
	/// a call to CSimpleSocket::Send waits until it completes. 
	/// @return the length of time in seconds
	i32 GetSendTimeoutSec(void) { return  m_stSendTimeout.tv_sec; };

	/// Gets the timeout value that specifies the maximum number of microseconds
	/// a call to CSimpleSocket::Send waits until it completes. 
	/// @return the length of time in microseconds
	i32 GetSendTimeoutUSec(void) { return  m_stSendTimeout.tv_usec; };

	/// Gets the timeout value that specifies the maximum amount of time a call 
	/// to CSimpleSocket::Send waits until it completes. 
	/// @return the length of time in seconds
	bool SetSendTimeout(i32 nSendTimeoutSec, i32 nSendTimeoutUsec = 0);

	/// Returns the last error that occured for the instace of the CSimpleSocket
	/// instance.  This method should be called immediately to retrieve the 
	/// error code for the failing mehtod call.
	///  @return last error that occured.
	CSocketError GetSocketError(void) { return m_socketErrno; };

	/// Return Differentiated Services Code Point (DSCP) value currently set on the socket object.
	/// @return DSCP for current socket object.
	/// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
	int GetSocketDscp(void);

	/// Set Differentiated Services Code Point (DSCP) for socket object.
	///  @param nDscp value of TOS setting which will be converted to DSCP
	///  @return true if DSCP value was properly set
	/// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
	bool SetSocketDscp(int nDscp);

	/// Return socket descriptor
	///  @return socket descriptor which is a signed 32 bit integer.
	SOCKET GetSocketDescriptor() { return m_socket; };

	/// Return socket descriptor
	///  @return socket descriptor which is a signed 32 bit integer.
	CSocketType GetSocketType() { return m_nSocketType; };

	/// Returns clients Internet host address as a string in standard numbers-and-dots notation.
	///  @return NULL if invalid
	u8 *GetClientAddr() { return (u8 *)inet_ntoa(m_stClientSockaddr.sin_addr); };

	/// Returns the port number on which the client is connected.
	///  @return client port number.
	i16 GetClientPort() { return m_stClientSockaddr.sin_port; };

	/// Returns server Internet host address as a string in standard numbers-and-dots notation.
	///  @return NULL if invalid
	u8 *GetServerAddr() { return (u8 *)inet_ntoa(m_stServerSockaddr.sin_addr); };

	/// Returns the port number on which the server is connected.
	///  @return server port number.
	i16 GetServerPort() { return ntohs(m_stServerSockaddr.sin_port); };

	/// Get the TCP receive buffer window size for the current socket object.
	/// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
	///  @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
	u16 GetReceiveWindowSize() { return GetWindowSize(SO_RCVBUF); };

	/// Get the TCP send buffer window size for the current socket object.
	/// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
	///  @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
	u16 GetSendWindowSize() { return GetWindowSize(SO_SNDBUF); };

	/// Set the TCP receive buffer window size for the current socket object.
	/// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
	///  @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
	u16 SetReceiveWindowSize(u16 nWindowSize) { return SetWindowSize(SO_RCVBUF, nWindowSize); };

	/// Set the TCP send buffer window size for the current socket object.
	/// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
	///  @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
	u16 SetSendWindowSize(u16 nWindowSize) { return SetWindowSize(SO_SNDBUF, nWindowSize); };

	/// Disable the Nagle algorithm (Set TCP_NODELAY to true)
	/// @return false if failed to set socket option otherwise return true;
	bool DisableNagleAlgoritm();

	/// Enable the Nagle algorithm (Set TCP_NODELAY to false)
	/// @return false if failed to set socket option otherwise return true;
	bool EnableNagleAlgoritm();

	void SetSocketError(TDSocket::CSocketError error) { m_socketErrno = error; };

	/// Set internal socket error to that specified error
	///  @param error type of error

	/// Set object socket handle to that specified as parameter 
	///  @param socket value of socket descriptor
	void SetSocketHandle(SOCKET socket) { m_socket = socket; };

	int SetSendBuffSize(int size);

	int SetRecvBuffSize(int size);

	std::string getClientIp();

	u16 getClientPort();

private:
	/// Generic function used to get the send/receive window size
	///  @return zero on failure else the number of bytes of the TCP window size if successful.
	u16 GetWindowSize(u32 nOptionName);

	/// Generic function used to set the send/receive window size
	///  @return zero on failure else the number of bytes of the TCP window size if successful.
	u16 SetWindowSize(u32 nOptionName, u32 nWindowSize);


	/// Attempts to send at most nNumItem blocks described by sendVector 
	/// to the socket descriptor associated with the socket object.
	/// @param sendVector pointer to an array of iovec structures
	/// @param nNumItems number of items in the vector to process
	/// <br>\b Note: This implementation is for systems that don't natively
	/// support this functionality.
	/// @return number of bytes actually sent, return of zero means the
	/// connection has been shutdown on the other side, and a return of -1
	/// means that an error has occurred.
	i32 Writev(const struct iovec *pVector, size_t nCount);

	/// Flush the socket descriptor owned by the object.
	/// @return true data was successfully sent, else return false;
	bool Flush();

	TDSocket *operator=(TDSocket &socket);



protected:
	SOCKET               m_socket;            /// socket handle
	CSocketError         m_socketErrno;       /// number of last error
	std::vector<u8>   m_pBuffer;           /// internal send/receive buffer
	i32                m_nBufferSize;       /// size of internal send/receive buffer
	i32                m_nSocketDomain;     /// socket type PF_INET, PF_INET6
	CSocketType          m_nSocketType;       /// socket type - UDP, TCP or RAW
	i32                m_nBytesReceived;    /// number of bytes received
	i32                m_nBytesSent;        /// number of bytes sent
	u32               m_nFlags;            /// socket flags
	bool                 m_bIsBlocking;       /// is socket blocking
	bool                 m_bIsMulticast;      /// is the UDP socket multicast;
	bool                 m_bIsConnect;
	struct timeval       m_stConnectTimeout;  /// connection timeout
	struct timeval       m_stRecvTimeout;     /// receive timeout
	struct timeval       m_stSendTimeout;     /// send timeout
	struct sockaddr_in   m_stServerSockaddr;  /// server address
	struct sockaddr_in   m_stClientSockaddr;  /// client address
	struct sockaddr_in   m_stMulticastGroup;  /// multicast group to bind to
	struct linger        m_stLinger;          /// linger flag
#ifdef WIN32
	WSADATA              m_hWSAData;          /// Windows
#endif 
	fd_set               m_writeFds;		  /// write file descriptor set
	fd_set               m_readFds;		      /// read file descriptor set
	fd_set               m_errorFds;		  /// error file descriptor set

public:
	virtual bool Open(const char *pAddr, i16 nPort);
private:
	/// Utility function used to create a TCP connection, called from Open().
	///  @return true if successful connection made, otherwise false.
	bool ConnectTCP(const char *pAddr, i16 nPort);

	/// Utility function used to create a UDP connection, called from Open().
	///  @return true if successful connection made, otherwise false.
	bool ConnectUDP(const char *pAddr, i16 nPort);

	/// Utility function used to create a RAW connection, called from Open().
	///  @return true if successful connection made, otherwise false.
	bool ConnectRAW(const char *pAddr, i16 nPort);

	public:
		/// Extracts the first connection request on the queue of pending 
		/// connections and creates a newly connected socket.  Used with 
		/// CSocketType CSimpleSocket::SocketTypeTcp.  It is the responsibility of
		/// the caller to delete the returned object when finished.
		///  @return if successful a pointer to a newly created CActiveSocket object
		///          will be returned and the internal error condition of the CPassiveSocket 
		///          object will be CPassiveSocket::SocketSuccess.  If an error condition was encountered
		///          the NULL will be returned and one of the following error conditions will be set:
		///    CPassiveSocket::SocketEwouldblock, CPassiveSocket::SocketInvalidSocket, 
		///    CPassiveSocket::SocketConnectionAborted, CPassiveSocket::SocketInterrupted
		///    CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketFirewallError
		virtual TDSocket *Accept(void);

		static int Accept(SOCKET socket, struct sockaddr* cli_addr, socklen_t sin_size);

		/// Bind to a multicast group on  a specified interface, multicast group, and port
		/// 
		///  @param pInterface - interface on which to bind.
		///  @param pGroup - multicast group address to bind.
		///  @param nPort - port on which multicast 
		///  @return true if able to bind to interface and multicast group.
		///      If not successful, the false is returned and one of the following error
		///      condiitions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, 
		///      CPassiveSocket::SocketInvalidSocket.  The following socket errors are for Linux/Unix
		///      derived systems only: CPassiveSocket::SocketInvalidSocketBuffer
		bool BindMulticast(const char *pInterface, const char *pGroup, i16 nPort);

		/// Create a listening socket at local ip address 'x.x.x.x' or 'localhost'
		/// if pAddr is NULL on port nPort.
		/// 
		///  @param pAddr specifies the IP address on which to listen.
		///  @param nPort specifies the port on which to listen.
		///  @param nConnectionBacklog specifies connection queue backlog (default 30,000)
		///  @return true if a listening socket was created.  
		///      If not successful, the false is returned and one of the following error
		///      condiitions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, 
		///      CPassiveSocket::SocketInvalidSocket.  The following socket errors are for Linux/Unix
		///      derived systems only: CPassiveSocket::SocketInvalidSocketBuffer
		virtual bool Listen(const char *pAddr, i16 nPort, i32 nConnectionBacklog = 300);

 private:
	 struct ip_mreq  m_stMulticastRequest;   /// group address for multicast
};



#endif // !_NET_BSSOCKET_H_

